''' <summary>
''' El PluginManager es el encargado de interactuar entre la aplicacion y los plugins (en primera instancia).
''' Provee funcionalidad para obtener los plugins cargados, cargar nuevos y notificar a los diferentes plugins.
''' </summary>
Public Class PluginManager
    Private _Plugins As List(Of Plugin)
    Private _PluginsPath As String = "Plugins/"
    Private _registeredPlugins As Generic.Dictionary(Of Plugin, List(Of String))
    Private _resources As Resources
    Public Sub New(ByRef resources As Resources)
        _Plugins = New List(Of Plugin)
        _registeredPlugins = New Generic.Dictionary(Of Plugin, List(Of String))
        _resources = resources
    End Sub
    ''' <summary>
    ''' Devuelve la lista de plugins cargados
    ''' </summary>
    ''' <value>List(Of Plugin)</value>
    ''' <returns>List(Of Plugin)</returns>
    Public ReadOnly Property Plugins() As List(Of Plugin)
        Get
            Return _Plugins
        End Get
    End Property
    ''' <summary>
    ''' Carga los plugins utilizando el PluginsPath
    ''' </summary>
    ''' <remarks><seealso cref="PluginManager.loadPlugins"></seealso></remarks>
    Public Sub loadPlugins()
        loadPlugins(_PluginsPath)
    End Sub
    ''' <summary>
    ''' Carga los plugins utilizando una rua especifica
    ''' </summary>
    ''' <param name="Folder"></param>
    ''' <remarks></remarks>
    Public Sub loadPlugins(ByVal Folder As String)
        Dim PluginFolder As IO.DirectoryInfo = New IO.DirectoryInfo(Folder)
        _Plugins.Clear()
        For Each file As IO.FileInfo In PluginFolder.GetFiles("*.ircx")
            Dim assembly As Reflection.Assembly = Reflection.Assembly.LoadFrom(file.FullName)
            For Each type As Type In assembly.GetTypes
                If type.Name.ToLower.IndexOf("plugin") > -1 Then
                    Dim plugin As Plugin = assembly.CreateInstance(type.FullName)
                    _Plugins.Add(plugin)
                    plugin.load(_resources)
                End If
            Next
        Next
    End Sub
    ''' <summary>
    ''' Esta funcion se encarga de chequear si un plugin esta registrado para ser notificado para un tipo de evento especifico
    ''' </summary>
    ''' <param name="targetPlugin">Plugin a chequear</param>
    ''' <param name="EventType">Evento a notificar</param>
    ''' <returns>True si esta registrado y puede ser notificado. False si no se encuentra registrado.</returns>
    Public Function isRegisteredForNotify(ByVal targetPlugin As Plugin, ByVal EventType As String) As Boolean

        If _registeredPlugins.ContainsKey(targetPlugin) Then
            Dim registeredEvents As List(Of String) = _registeredPlugins(targetPlugin)
            Return registeredEvents.Contains(EventType)
        End If
        Return False
    End Function

    ''' <summary>
    ''' Registra el plugin para el evento especificado.
    ''' </summary>
    ''' <param name="EventType">Evento al cual registrarse</param>
    Public Function registerForNotify(ByRef plugin As Plugin, ByVal EventType As String) As Boolean
        If Not isRegisteredForNotify(plugin, EventType) Then
            If Not _registeredPlugins.ContainsKey(plugin) Then
                _registeredPlugins.Add(plugin, New List(Of String))
            End If
            Dim registeredEvents As List(Of String) = _registeredPlugins(plugin)
            registeredEvents.Add(EventType)
            Return True
        End If
    End Function
    ''' <summary>
    ''' Elimina el plugin para el evento especificado.
    ''' </summary>
    ''' <param name="EventType">Evento al cual dejar de estar registrado</param>
    Public Function unregisterForNotify(ByRef plugin As Plugin, ByVal EventType As String) As Boolean
        If isRegisteredForNotify(plugin, EventType) Then
            Dim registeredEvents As List(Of String) = _registeredPlugins(plugin)
            registeredEvents.Remove(EventType)
            Return True
        Else
            Throw New InvalidOperationException("The Plugin " & plugin.getPluginInfo().Name & " is not registered for event: " + EventType)
        End If
    End Function
    ''' <summary>
    ''' Notifica a los plugins registrados para el evento a notificar utilizando el metodo Process de cada Plugin
    ''' </summary>
    ''' <param name="notifiableEvent">Evento disparado</param>
    ''' <param name="package">Package con datos correspodientes al evento</param>
    ''' <remarks></remarks>
    Public Sub notify(ByRef notifiableEvent As NotifiableEvent, ByRef package As Package)
        For Each loadedPlugin As Plugin In _Plugins
            If isRegisteredForNotify(loadedPlugin, notifiableEvent.getEventType) Then
                loadedPlugin.Process(notifiableEvent, package)
            End If
        Next
    End Sub
    ''' <summary>
    ''' Descarga los plugins. Los elimina.
    ''' </summary>
    Public Sub unloadPlugins()
        For Each plugin As Plugin In _Plugins
            plugin.unload()
        Next
        _Plugins.Clear()
        _registeredPlugins.Clear()
    End Sub
End Class
